// Copyright (c) MatrixFramework. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using MatrixFramework.Keycloak.Abstractions.Services;
using MatrixFramework.Keycloak.Abstractions.Options;
using MatrixFramework.Keycloak.Abstractions.Models;

namespace MatrixFramework.Keycloak.Abstractions.Extensions;

/// <summary>
/// 服务集合扩展方法
/// </summary>
public static class ServiceCollectionExtensions
{
    /// <summary>
    /// 添加MatrixFramework Keycloak服务
    /// </summary>
    /// <param name="services">服务集合</param>
    /// <param name="configuration">配置</param>
    /// <returns>服务集合</returns>
    public static IServiceCollection AddMatrixKeycloak(
        this IServiceCollection services,
        IConfiguration configuration)
    {
        return services.AddMatrixKeycloak(configuration, options => { });
    }

    /// <summary>
    /// 添加MatrixFramework Keycloak服务
    /// </summary>
    /// <param name="services">服务集合</param>
    /// <param name="configuration">配置</param>
    /// <param name="configureOptions">配置选项</param>
    /// <returns>服务集合</returns>
    public static IServiceCollection AddMatrixKeycloak(
        this IServiceCollection services,
        IConfiguration configuration,
        Action<KeycloakOptions> configureOptions)
    {
        // 绑定配置
        services.Configure<KeycloakOptions>(KeycloakOptions.SectionName, configuration);
        services.PostConfigure<KeycloakOptions>(options =>
        {
            configureOptions?.Invoke(options);
            ValidateOptions(options);
        });

        // 注册服务
        services.AddKeycloakServices();

        return services;
    }

    /// <summary>
    /// 添加MatrixFramework Keycloak服务
    /// </summary>
    /// <param name="services">服务集合</param>
    /// <param name="configureOptions">配置选项</param>
    /// <returns>服务集合</returns>
    public static IServiceCollection AddMatrixKeycloak(
        this IServiceCollection services,
        Action<KeycloakOptions> configureOptions)
    {
        // 配置选项
        services.Configure(configureOptions);
        services.PostConfigure<KeycloakOptions>(options => ValidateOptions(options));

        // 注册服务
        services.AddKeycloakServices();

        return services;
    }

    /// <summary>
    /// 添加MatrixFramework Keycloak服务（使用默认配置）
    /// </summary>
    /// <param name="services">服务集合</param>
    /// <returns>服务集合</returns>
    public static IServiceCollection AddMatrixKeycloak(this IServiceCollection services)
    {
        services.PostConfigure<KeycloakOptions>(options => ValidateOptions(options));
        services.AddKeycloakServices();

        return services;
    }

    /// <summary>
    /// 注册Keycloak核心服务（仅注册接口定义，具体实现在应用层注册）
    /// </summary>
    /// <param name="services">服务集合</param>
    /// <returns>服务集合</returns>
    internal static IServiceCollection AddKeycloakServices(this IServiceCollection services)
    {
        // 注意：具体服务实现(IKeycloakAdminService)的注册
        // 应该在使用方（如Host项目）中进行，这里只提供配置和接口定义

        // 注意：HealthChecks暂时移除，待后续版本重新添加
        // services.AddHealthChecks()
        //     .AddCheck<KeycloakHealthCheck>("keycloak");

        return services;
    }

    /// <summary>
    /// 添加Keycloak多租户支持
    /// </summary>
    /// <param name="services">服务集合</param>
    /// <param name="configureMultiTenant">多租户配置</param>
    /// <returns>服务集合</returns>
    public static IServiceCollection AddKeycloakMultiTenant(
        this IServiceCollection services,
        Action<MultiTenantOptions>? configureMultiTenant = null)
    {
        services.PostConfigure<KeycloakOptions>(options =>
        {
            configureMultiTenant?.Invoke(options.MultiTenant);
            ValidateMultiTenantOptions(options.MultiTenant);
        });

        // 注意：多租户相关服务的具体实现注册
        // 应该在使用方（如Host项目）中进行，这里只提供接口定义

        return services;
    }

    /// <summary>
    /// 添加Keycloak客户端工厂（仅接口注册，具体实现注册在应用层进行）
    /// </summary>
    /// <param name="services">服务集合</param>
    /// <returns>服务集合</returns>
    public static IServiceCollection AddKeycloakClientFactory(this IServiceCollection services)
    {
        // 注意：具体实现(IKeycloakClientFactory)的注册应该在使用方进行
        // 这里只提供接口定义
        return services;
    }

    /// <summary>
    /// 验证配置选项
    /// </summary>
    /// <param name="options">配置选项</param>
    /// <exception cref="ArgumentException">配置无效时抛出</exception>
    private static void ValidateOptions(KeycloakOptions options)
    {
        if (string.IsNullOrWhiteSpace(options.BaseUrl))
            throw new ArgumentException("Keycloak BaseUrl 不能为空", nameof(options));

        if (!Uri.TryCreate(options.BaseUrl, UriKind.Absolute, out _))
            throw new ArgumentException("Keycloak BaseUrl 必须是有效的URI", nameof(options));

        if (string.IsNullOrWhiteSpace(options.AdminClientId))
            throw new ArgumentException("AdminClientId 不能为空", nameof(options));

        if (string.IsNullOrWhiteSpace(options.AdminClientSecret))
            throw new ArgumentException("AdminClientSecret 不能为空", nameof(options));

        if (string.IsNullOrWhiteSpace(options.DefaultRealm))
            throw new ArgumentException("DefaultRealm 不能为空", nameof(options));

        if (string.IsNullOrWhiteSpace(options.AdminUsername))
            throw new ArgumentException("AdminUsername 不能为空", nameof(options));

        if (string.IsNullOrWhiteSpace(options.AdminPassword))
            throw new ArgumentException("AdminPassword 不能为空", nameof(options));

        if (options.TimeoutSeconds < 1 || options.TimeoutSeconds > 300)
            throw new ArgumentException("TimeoutSeconds 必须在1-300秒之间", nameof(options));

        if (options.RetryCount < 0 || options.RetryCount > 10)
            throw new ArgumentException("RetryCount 必须在0-10次之间", nameof(options));

        if (options.RetryDelayMs < 100 || options.RetryDelayMs > 60000)
            throw new ArgumentException("RetryDelayMs 必须在100-60000毫秒之间", nameof(options));

        if (options.TokenExpirationBufferMinutes < 1 || options.TokenExpirationBufferMinutes > 60)
            throw new ArgumentException("TokenExpirationBufferMinutes 必须在1-60分钟之间", nameof(options));
    }

    /// <summary>
    /// 验证多租户配置选项
    /// </summary>
    /// <param name="options">多租户配置选项</param>
    /// <exception cref="ArgumentException">配置无效时抛出</exception>
    private static void ValidateMultiTenantOptions(MultiTenantOptions options)
    {
        if (options.Enabled && string.IsNullOrWhiteSpace(options.TenantPrefix))
            throw new ArgumentException("启用多租户时，TenantPrefix 不能为空", nameof(options));

        if (options.Enabled && string.IsNullOrWhiteSpace(options.DefaultRealmTemplate))
            throw new ArgumentException("启用多租户时，DefaultRealmTemplate 不能为空", nameof(options));
    }
}